#pragma once
#include <pthread.h>
#include <unordered_map>
#include "util.hpp"
#include "config.hpp"

namespace cloud
{
    // 备份的文件的信息
    class backup_info
    {
    public:
        bool _pack_flag;        // 标志文件是否被压缩
        int64_t _fsize;         // 文件大小
        time_t _atime;          // 最后一次访问文件的时间
        time_t _mtime;          // 最后一次修改文件的时间
        std::string _real_path; // 文件真实路径
        std::string _pack_path; // 压缩后文件路径
        std::string _url;       // 文件下载路径
    
    public:
        backup_info(){}

        backup_info(const std::string &real_path)
        {
            init(real_path);
        }

        // 根据文件路径获取文件信息
        void init(const std::string &real_path)
        {
            file_util fu(real_path);
            if (fu.exist() == false)
            {
                ERROR("backup_info 文件不存在");
                // std::cout << "backup_info 文件不存在" << std::endl;
            }
            else
            {
                _pack_flag = false;
                _real_path = real_path;
                _fsize = fu.file_size();
                _atime = fu.last_access_time();
                _mtime = fu.last_modify_time();

                config *c = config::get_instance();
                std::string pack_dir = c->get_pack_dir();
                std::string pack_suffix = c->get_packfile_suffix();
                // ./backdir/a.txt --> ./packdir/a.txt.lz
                _pack_path = pack_dir + fu.file_name() + pack_suffix;

                std::string download_prefix = c->get_download_prefix();
                // ./backdir/a.txt --> /download/a.txt
                _url = download_prefix + fu.file_name();

                //INFO("backup_info 文件信息初始化完毕 --> %s", _real_path.c_str());
            }
        }

        void print()
        {
            file_util fu(_real_path);
            if(fu.exist() == false)
            {
                ERROR("backup_info 文件不存在,real_path为%s", _real_path.c_str());
                // std::cout << "backup_info 文件不存在" << std::endl;
                return;
            }
            std::cout << "_pack_flag:" << _pack_flag << std::endl;
            std::cout << "_fsize:"  << _fsize << std::endl;
            std::cout << "_atime:"  << _atime << std::endl;
            std::cout << "_mtime:"  << _mtime << std::endl;
            std::cout << "_real_path:"  << _real_path << std::endl;
            std::cout << "_pack_path:"  << _pack_path << std::endl;
            std::cout << "_url:"  << _url << std::endl;
        }
    };

    class data_manage
    {
    public:
        data_manage()
        {
            _backup_file = config::get_instance()->get_backup_file();
            pthread_rwlock_init(&_rwlock, nullptr);
            init();
        }

        ~data_manage()
        {
            pthread_rwlock_destroy(&_rwlock);
        }

        // 启动时从_backup_file中读取数据初始化
        void init()
        {
            file_util fu(_backup_file);
            if(fu.exist() == false)
            {
                // 没有备份信息文件，无须初始化
                INFO("没有备份信息文件，创建之");
                // std::cout << "没有备份信息文件，创建之" << std::endl;
                FILE* fd = fopen(_backup_file.c_str(), "w");
                fclose(fd);
                return;
            }

            // 反序列化
            Json::Value root;
            std::string data;
            fu.get_content(data);
            if(data.size() == 0)
                return;
            json_util::deserialize(root, data);

            // 将备份信息文件的信息添加到数据哈希表中
            for(int i = 0; i < root.size(); ++i)
            {
                backup_info info;
                info._pack_flag = root[i]["_pack_flag"].asBool();
                info._fsize = root[i]["_fsize"].asInt64();
                info._atime = root[i]["_atime"].asInt64();
                info._mtime = root[i]["_mtime"].asInt64();
                info._pack_path = root[i]["_pack_path"].asString();
                info._real_path = root[i]["_real_path"].asString();
                info._url = root[i]["_url"].asString();
                insert(info);
            }
        }

        bool insert(const backup_info &info)
        {
            pthread_rwlock_wrlock(&_rwlock); //加写锁
            _datas[info._url] = info;
            storage();
            pthread_rwlock_unlock(&_rwlock); //解锁
            return true;
        }

        // 更新，修改文件数据
        bool updata(const backup_info &info)
        {
            pthread_rwlock_wrlock(&_rwlock); //加写锁
            _datas[info._url] = info;
            storage();
            pthread_rwlock_unlock(&_rwlock); //解锁
            return true;
        }

        // 根据url获取文件信息
        bool get_one_by_url(const std::string &url, backup_info &info)
        {
            pthread_rwlock_rdlock(&_rwlock); //加读锁
            auto it = _datas.find(url);
            if(it == _datas.end())
            {
                std::cout << "未找到url，url为" << url << endl;
                std::vector<backup_info> v;
                get_all(v);
                for(auto& x : v)
                    x.print();
                pthread_rwlock_unlock(&_rwlock); //解锁
                return false;
            }
            info = it->second;
            pthread_rwlock_unlock(&_rwlock); //解锁
            return true;
        }

        // 根据realpath获取文件信息
        bool get_one_by_realpath(const std::string &realpath, backup_info &info)
        {
            pthread_rwlock_rdlock(&_rwlock); //加读锁
            for(auto &it : _datas)
            {
                if(it.second._real_path == realpath)
                {
                    info = it.second;
                    pthread_rwlock_unlock(&_rwlock); //解锁
                    return true;
                }
            }
            pthread_rwlock_unlock(&_rwlock); //解锁
            return false;
        }

        // 获取全部文件信息
        bool get_all(std::vector<backup_info> &v)
        {
            pthread_rwlock_rdlock(&_rwlock); //加读锁
            for(auto &it : _datas)
            {
                v.push_back(it.second);
            }
            pthread_rwlock_unlock(&_rwlock); //解锁
            return true;
        }

        // 文件信息持久化
        bool storage()
        {
            Json::Value root;
            for(auto &it : _datas)
            {
                Json::Value item;
                item["_pack_flag"] = it.second._pack_flag;
                item["_fsize"] = (Json::Int64)it.second._fsize;
                item["_atime"] = (Json::Int64)it.second._atime;
                item["_mtime"] = (Json::Int64)it.second._mtime;
                item["_real_path"] = it.second._real_path;
                item["_pack_path"] = it.second._pack_path;
                item["_url"] = it.second._url;
                root.append(item);
            }

            // 序列化
            std::string data;
            json_util::serialize(root, data);

            file_util fu(_backup_file);
            fu.set_content(data);
            return true;
        }

        
    private:
        std::string _backup_file;                            // 服务端备份信息存放文件
        pthread_rwlock_t _rwlock;                            // 读写锁
        std::unordered_map<std::string, backup_info> _datas; // 数据哈希表
    };
}